Skip to content

chore: effect rpc and layer based startup#929

Merged
juliusmarminge merged 68 commits intomainfrom
effect-http-router
Apr 1, 2026
Merged

chore: effect rpc and layer based startup#929
juliusmarminge merged 68 commits intomainfrom
effect-http-router

Conversation

@juliusmarminge
Copy link
Copy Markdown
Member

@juliusmarminge juliusmarminge commented Mar 11, 2026

What Changed

Why

UI Changes

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

High Risk
Large refactor of server boot/routing and WebSocket RPC surfaces plus packaging entrypoints; regressions could prevent the server or desktop app from starting or serving assets/RPC correctly.

Overview
Server startup is refactored to a new Effect CLI (src/bin.ts + src/cli.ts) that resolves config from flags/env/bootstrap FD, ensures runtime directories exist, and launches a new Layer-composed server (src/server.ts) instead of the previous main.ts/index.ts wiring.

The server now exposes a unified router (src/http.ts) for static/dev redirect, attachments file serving, and project favicon requests, and adds/expands a WebSocket RPC route (/ws) with new seam tests (server.test.ts); lifecycle event streaming is formalized via a new ServerLifecycleEvents service.

Cross-cutting cleanup moves several domain error types (git/text-generation/keybindings/open/server-settings) to @t3tools/contracts, removes bespoke logger code, updates GitCore background refresh to detached fibers, and adjusts desktop + server packaging to use dist/bin.mjs (including dev-electron watcher updates) while increasing various integration test timeouts and adding required WorkspacePaths wiring.

Written by Cursor Bugbot for commit 0bb9550. This will update automatically on new commits. Configure here.

Note

Replace WebSocket push/subscribe transport with Effect RPC client and atom-backed server state

  • Replaces the legacy WsTransport push/channel model with an Effect-based RPC protocol client (WsRpcGroup) for both the web client and server, using JSON serialization and automatic transient-error retry.
  • Introduces atom-backed server state (serverState.ts) via @effect/atom-react for server config, keybindings, providers, and lifecycle events, replacing React Query throughout ChatView, Sidebar, SettingsPanels, and related components.
  • Adds a full WebSocket RPC layer on the server (ws.ts) integrating orchestration, git, terminal, workspace, and lifecycle endpoints with typed contract errors sourced from @t3tools/contracts.
  • Migrates shared error types (GitCommandError, TextGenerationError, KeybindingsConfigError, ServerSettingsError, etc.) from local definitions into the @t3tools/contracts package and removes git/Errors.ts.
  • Introduces ServerRuntimeStartup with a CommandGate that queues RPC commands until the server is ready, and adds ServerLifecycleEvents for publishing and snapshotting welcome/ready lifecycle events.
  • Changes the server binary entry from index.ts to bin.ts, adds @effect/platform-bun for platform-specific HTTP/WebSocket serving, and removes ws/@types/ws dependencies.
  • Risk: NativeApi no longer exposes runStackedAction or onActionProgress directly; git action progress is now wired through the mutation's onProgress callback and the RPC client stream.

Macroscope summarized 0bb9550.

@juliusmarminge juliusmarminge marked this pull request as draft March 11, 2026 18:53
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 11, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ab424688-f999-4662-bbae-2bf3a97edbcf

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch effect-http-router

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added the vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. label Mar 11, 2026
Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Dev URL redirect drops request path and query
    • Fixed the redirect to construct a new URL from the request's pathname and search params against the dev origin, and updated the test to assert the correct behavior.

Create PR

Or push these changes by commenting:

@cursor push 089fb595df
Preview (089fb595df)
diff --git a/apps/server/src/http.ts b/apps/server/src/http.ts
--- a/apps/server/src/http.ts
+++ b/apps/server/src/http.ts
@@ -90,7 +90,8 @@
 
     const config = yield* ServerConfig;
     if (config.devUrl) {
-      return HttpServerResponse.redirect(config.devUrl.href, { status: 302 });
+      const devTarget = new URL(`${url.pathname}${url.search}`, config.devUrl);
+      return HttpServerResponse.redirect(devTarget.href, { status: 302 });
     }
 
     if (!config.staticDir) {

diff --git a/apps/server/src/server.test.ts b/apps/server/src/server.test.ts
--- a/apps/server/src/server.test.ts
+++ b/apps/server/src/server.test.ts
@@ -266,7 +266,7 @@
       const response = yield* Effect.promise(() => fetch(url, { redirect: "manual" }));
 
       assert.equal(response.status, 302);
-      assert.equal(response.headers.get("location"), "http://127.0.0.1:5173/");
+      assert.equal(response.headers.get("location"), "http://127.0.0.1:5173/foo/bar");
     }).pipe(Effect.provide(NodeHttpServer.layerTest)),
   );


const config = yield* ServerConfig;
if (config.devUrl) {
return HttpServerResponse.redirect(config.devUrl.href, { status: 302 });
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dev URL redirect drops request path and query

High Severity

The dev URL redirect uses config.devUrl.href without appending the incoming request's pathname or search params. Every GET request (e.g. /settings?tab=general) redirects to the dev server root (http://127.0.0.1:5173/) instead of the matching route (http://127.0.0.1:5173/settings?tab=general). The reference implementation correctly constructs new URL(url.pathname + url.search, origin). The test at line 269 asserts the broken behavior, masking the regression.

Additional Locations (1)
Fix in Cursor Fix in Web

@github-actions github-actions bot added the size:XXL 1,000+ changed lines (additions + deletions). label Mar 13, 2026
- move project favicon resolution into the Effect HTTP router
- create derived runtime directories during config resolution
- update desktop/server entrypoints and web URL helpers
Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 4 total unresolved issues (including 3 from previous reviews).

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Git error message loses operation/command/cwd context
    • Restored the rich formatted message getters in all four error classes (GitCommandError, GitHubCliError, TextGenerationError, GitManagerError) in packages/contracts/src/git.ts to include operation, command, and cwd context, matching the original local definitions.

Create PR

Or push these changes by commenting:

@cursor push 5eba9380c8
Preview (5eba9380c8)
diff --git a/packages/contracts/src/git.ts b/packages/contracts/src/git.ts
--- a/packages/contracts/src/git.ts
+++ b/packages/contracts/src/git.ts
@@ -232,7 +232,7 @@
   cause: Schema.optional(Schema.Defect),
 }) {
   override get message(): string {
-    return this.detail;
+    return `Git command failed in ${this.operation}: ${this.command} (${this.cwd}) - ${this.detail}`;
   }
 }
 
@@ -242,7 +242,7 @@
   cause: Schema.optional(Schema.Defect),
 }) {
   override get message(): string {
-    return this.detail;
+    return `GitHub CLI failed in ${this.operation}: ${this.detail}`;
   }
 }
 
@@ -255,7 +255,7 @@
   },
 ) {
   override get message(): string {
-    return this.detail;
+    return `Text generation failed in ${this.operation}: ${this.detail}`;
   }
 }
 
@@ -265,7 +265,7 @@
   cause: Schema.optional(Schema.Defect),
 }) {
   override get message(): string {
-    return this.detail;
+    return `Git manager failed in ${this.operation}: ${this.detail}`;
   }
 }

You can send follow-ups to this agent here.

@juliusmarminge
Copy link
Copy Markdown
Member Author

@cursor push 5eba938

The message getters for GitCommandError, GitHubCliError, TextGenerationError,
and GitManagerError in contracts were returning only this.detail, losing the
operation, command, and cwd context that the original local definitions
included. Restore the formatted messages so that logging and error reporting
surfaces full debugging context.

Applied via @cursor push command
Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 4 total unresolved issues (including 3 from previous reviews).

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Stricter bootstrap schema silently breaks graceful fallback
    • Changed BootstrapEnvelopeSchema mode field back to Schema.optional(Schema.String) and added an isRuntimeMode filter at resolution time so unrecognized mode values are silently ignored and fall back to "web".

Create PR

Or push these changes by commenting:

@cursor push 4405ddf176
Preview (4405ddf176)
diff --git a/apps/server/src/cli.ts b/apps/server/src/cli.ts
--- a/apps/server/src/cli.ts
+++ b/apps/server/src/cli.ts
@@ -17,8 +17,10 @@
 
 const PortSchema = Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 65535 }));
 
+const isRuntimeMode = Schema.is(RuntimeMode);
+
 const BootstrapEnvelopeSchema = Schema.Struct({
-  mode: Schema.optional(RuntimeMode),
+  mode: Schema.optional(Schema.String),
   port: Schema.optional(PortSchema),
   host: Schema.optional(Schema.String),
   t3Home: Schema.optional(Schema.String),
@@ -148,7 +150,9 @@
       resolveOptionPrecedence(
         flags.mode,
         Option.fromUndefinedOr(env.mode),
-        Option.flatMap(bootstrapEnvelope, (bootstrap) => Option.fromUndefinedOr(bootstrap.mode)),
+        Option.flatMap(bootstrapEnvelope, (bootstrap) =>
+          Option.filter(Option.fromUndefinedOr(bootstrap.mode), isRuntimeMode),
+        ),
       ),
       () => "web",
     );

You can send follow-ups to this agent here.

Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 5 total unresolved issues (including 4 from previous reviews).

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Background git refresh loses all services with Effect.runFork
    • Restored Effect.forkScoped in place of Effect.sync(() => { Effect.runFork(...) }) which was incorrectly introduced during a merge, so the background upstream refresh now inherits all service layers from the enclosing scope.

Create PR

Or push these changes by commenting:

@cursor push 460b46b80b
Preview (460b46b80b)
diff --git a/apps/server/src/git/Layers/GitCore.ts b/apps/server/src/git/Layers/GitCore.ts
--- a/apps/server/src/git/Layers/GitCore.ts
+++ b/apps/server/src/git/Layers/GitCore.ts
@@ -1941,11 +1941,9 @@
       });
 
       // Refresh upstream refs in the background so checkout remains responsive.
-      yield* Effect.sync(() => {
-        Effect.runFork(
-          refreshCheckedOutBranchUpstream(input.cwd).pipe(Effect.ignoreCause({ log: true })),
-        );
-      });
+      yield* Effect.forkScoped(
+        refreshCheckedOutBranchUpstream(input.cwd).pipe(Effect.ignoreCause({ log: true })),
+      );
     },
   );

You can send follow-ups to this agent here.

- Route workspace lookups through shared path normalization
- Inline the project favicon fallback and remove the health route
- Update tests for normalized workspace errors and favicon serving
- Return progress events inline from git.runStackedAction
- Remove the separate git action progress subscription path
- Update web/native clients and tests to consume streamed results
- Remove trailing commas from `apps/web/tsconfig.json`
- Keep TypeScript config consistent with project formatting rules
- Move WebSocket RPC schemas into `contracts/rpc`
- Rename welcome payload to `ServerLifecycleWelcomePayload`
- Update server attachment serving to use file responses
- Extract shared websocket RPC protocol layer
- Add atom-backed RPC client and registry provider
- Update transport and tests for the new client path
- Centralize server config and welcome state in `rpc/serverState`
- Bootstrap server snapshots from the RPC client in one place
- Update web consumers and tests for the new server state flow
Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

There are 3 total unresolved issues (including 1 from previous review).

Fix All in Cursor

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Planning doc committed with developer-local absolute paths
    • Replaced all 25 occurrences of the developer-local absolute path prefix /Users/julius/.t3/worktrees/codething-mvp/effect-http-router/ with empty string, making all markdown links use repository-relative paths.
  • ✅ Fixed: Detached fork leaks fiber beyond scope lifetime
    • Restored Effect.forkScoped (replacing Effect.forkDetach({ startImmediately: true })) so the background upstream refresh fiber is tied to the enclosing scope and properly interrupted during shutdown, consistent with the type signature requiring Scope.Scope.

Create PR

Or push these changes by commenting:

@cursor push bd40a77074
Preview (bd40a77074)
diff --git a/.plans/effect-atom.md b/.plans/effect-atom.md
--- a/.plans/effect-atom.md
+++ b/.plans/effect-atom.md
@@ -1,20 +1,20 @@
 # Replace React Query With AtomRpc + Atom State
 
 ## Summary
-- Use `effect/unstable/reactivity/AtomRpc` over the existing `WsRpcGroup`; stop wrapping RPC in promises via [wsRpcClient.ts](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/apps/web/src/wsRpcClient.ts) and [wsNativeApi.ts](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/apps/web/src/wsNativeApi.ts).
+- Use `effect/unstable/reactivity/AtomRpc` over the existing `WsRpcGroup`; stop wrapping RPC in promises via [wsRpcClient.ts](apps/web/src/wsRpcClient.ts) and [wsNativeApi.ts](apps/web/src/wsNativeApi.ts).
 - Keep Zustand for orchestration read model and UI state.
 - Keep a narrow `desktopBridge` adapter for dialogs, menus, external links, theme, and updater APIs.
 - Do not introduce Suspense in this migration. Atom-backed hooks should keep returning `data`, `error`, `isLoading|isPending`, `refresh`, and `mutateAsync`-style surfaces so component churn stays low.
 
 ## Target Architecture
-- Extract the websocket `RpcClient.Protocol` layer from [wsTransport.ts](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/apps/web/src/wsTransport.ts) into `rpc/protocol.ts`.
+- Extract the websocket `RpcClient.Protocol` layer from [wsTransport.ts](apps/web/src/wsTransport.ts) into `rpc/protocol.ts`.
 - Define one `AtomRpc.Service` for `WsRpcGroup` in `rpc/client.ts`.
 - Add `rpc/invalidation.ts` with explicit scoped invalidation keys: `git:${cwd}`, `project:${cwd}`, `checkpoint:${threadId}`, `server-config`.
 - Add `platform/desktopBridge.ts` as the only browser/desktop facade.
-- Remove from web by the end: [wsNativeApi.ts](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/apps/web/src/wsNativeApi.ts), [nativeApi.ts](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/apps/web/src/nativeApi.ts), [wsNativeApiState.ts](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/apps/web/src/wsNativeApiState.ts), [wsNativeApiAtoms.tsx](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/apps/web/src/wsNativeApiAtoms.tsx), [wsRpcClient.ts](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/apps/web/src/wsRpcClient.ts), and all `*ReactQuery.ts` modules.
+- Remove from web by the end: [wsNativeApi.ts](apps/web/src/wsNativeApi.ts), [nativeApi.ts](apps/web/src/nativeApi.ts), [wsNativeApiState.ts](apps/web/src/wsNativeApiState.ts), [wsNativeApiAtoms.tsx](apps/web/src/wsNativeApiAtoms.tsx), [wsRpcClient.ts](apps/web/src/wsRpcClient.ts), and all `*ReactQuery.ts` modules.
 
 ## Phase 1: Infrastructure First
-1. Extract the shared websocket RPC protocol layer from [wsTransport.ts](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/apps/web/src/wsTransport.ts) without changing behavior.
+1. Extract the shared websocket RPC protocol layer from [wsTransport.ts](apps/web/src/wsTransport.ts) without changing behavior.
 2. Build the AtomRpc client on top of that layer.
 3. Add one temporary `runRpc` helper for imperative handlers that still want `Promise` ergonomics; it must call the AtomRpc service directly and must not reintroduce a facade object.
 4. Replace manual registry wiring with one app-level registry provider based on `@effect/atom-react`.
@@ -22,21 +22,21 @@
 
 ## Phase 2: Replace `wsNativeApi`-Owned Push State
 1. Migrate welcome/config/provider/settings state first, because it is already atom-shaped and is the lowest-risk way to delete `wsNativeApi` responsibilities.
-2. Replace [wsNativeApiState.ts](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/apps/web/src/wsNativeApiState.ts) with `rpc/serverState.ts`, updated directly from `subscribeServerLifecycle` and `subscribeServerConfig`.
+2. Replace [wsNativeApiState.ts](apps/web/src/wsNativeApiState.ts) with `rpc/serverState.ts`, updated directly from `subscribeServerLifecycle` and `subscribeServerConfig`.
 3. Keep the current hook names for one PR: `useServerConfig`, `useServerSettings`, `useServerProviders`, `useServerKeybindings`, `useServerWelcomeSubscription`, `useServerConfigUpdatedSubscription`.
-4. Move bootstrap side effects out of [wsNativeApiAtoms.tsx](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/apps/web/src/wsNativeApiAtoms.tsx) into a new root bootstrap component mounted from [__root.tsx](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/apps/web/src/routes/__root.tsx).
-5. Delete the `server.getConfig()` fallback logic from [wsNativeApi.ts](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/apps/web/src/wsNativeApi.ts); snapshot fetch now lives beside the stream atoms.
+4. Move bootstrap side effects out of [wsNativeApiAtoms.tsx](apps/web/src/wsNativeApiAtoms.tsx) into a new root bootstrap component mounted from [__root.tsx](apps/web/src/routes/__root.tsx).
+5. Delete the `server.getConfig()` fallback logic from [wsNativeApi.ts](apps/web/src/wsNativeApi.ts); snapshot fetch now lives beside the stream atoms.
 
 ## Phase 3: Replace React Query Domain By Domain
-1. Replace [gitReactQuery.ts](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/apps/web/src/lib/gitReactQuery.ts) first.
+1. Replace [gitReactQuery.ts](apps/web/src/lib/gitReactQuery.ts) first.
 2. Add `rpc/gitAtoms.ts` and `rpc/useGit.ts` with `useGitStatus`, `useGitBranches`, `useResolvePullRequest`, and `useGitMutation`.
 3. Mutation settlement must invalidate scoped keys, not a global cache. `checkout`, `pull`, `init`, `createWorktree`, `removeWorktree`, `preparePullRequestThread`, and stacked actions invalidate `git:${cwd}`. Worktree create/remove also invalidates `project:${cwd}`.
-4. Replace [projectReactQuery.ts](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/apps/web/src/lib/projectReactQuery.ts) second. `useProjectSearchEntries` must preserve current “keep previous results while loading” behavior.
-5. Replace [providerReactQuery.ts](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/apps/web/src/lib/providerReactQuery.ts) third. Preserve current checkpoint error normalization and retry/backoff semantics inside the atom effect. Invalidate by `checkpoint:${threadId}`.
+4. Replace [projectReactQuery.ts](apps/web/src/lib/projectReactQuery.ts) second. `useProjectSearchEntries` must preserve current “keep previous results while loading” behavior.
+5. Replace [providerReactQuery.ts](apps/web/src/lib/providerReactQuery.ts) third. Preserve current checkpoint error normalization and retry/backoff semantics inside the atom effect. Invalidate by `checkpoint:${threadId}`.
 6. Defer the desktop updater until the last phase.
 
 ## Phase 4: Move Root Invalidation Off `queryClient`
-1. In [__root.tsx](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/apps/web/src/routes/__root.tsx), remove `QueryClient` usage and replace the throttled `invalidateQueries` block with throttled invalidation helpers.
+1. In [__root.tsx](apps/web/src/routes/__root.tsx), remove `QueryClient` usage and replace the throttled `invalidateQueries` block with throttled invalidation helpers.
 2. Keep Zustand orchestration/event application unchanged.
 3. Map current effects exactly:
 - git or checkpoint-affecting orchestration events touch `checkpoint:${threadId}`
@@ -50,14 +50,14 @@
 - `rpc/gitActions.ts`
 - `rpc/projectActions.ts`
 - `platform/desktopBridge.ts`
-2. Migrate direct [nativeApi.ts](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/apps/web/src/nativeApi.ts) callers by domain, not file-by-file: git-heavy components first, then orchestration/thread actions, then shell/dialog helpers.
-3. After the last caller is gone, delete [nativeApi.ts](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/apps/web/src/nativeApi.ts) and the `window.nativeApi` fallback entirely.
-4. In the final cleanup PR, remove `NativeApi` from [ipc.ts](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/packages/contracts/src/ipc.ts) if nothing outside web still needs it.
+2. Migrate direct [nativeApi.ts](apps/web/src/nativeApi.ts) callers by domain, not file-by-file: git-heavy components first, then orchestration/thread actions, then shell/dialog helpers.
+3. After the last caller is gone, delete [nativeApi.ts](apps/web/src/nativeApi.ts) and the `window.nativeApi` fallback entirely.
+4. In the final cleanup PR, remove `NativeApi` from [ipc.ts](packages/contracts/src/ipc.ts) if nothing outside web still needs it.
 
 ## Phase 6: Remove React Query Completely
 1. Delete `@tanstack/react-query` from `apps/web/package.json`.
-2. Remove `QueryClientProvider` and router context from [router.ts](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/apps/web/src/router.ts) and [__root.tsx](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/apps/web/src/routes/__root.tsx).
-3. Replace [desktopUpdateReactQuery.ts](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/apps/web/src/lib/desktopUpdateReactQuery.ts) with a writable atom plus `desktopBridge.onUpdateState`.
+2. Remove `QueryClientProvider` and router context from [router.ts](apps/web/src/router.ts) and [__root.tsx](apps/web/src/routes/__root.tsx).
+3. Replace [desktopUpdateReactQuery.ts](apps/web/src/lib/desktopUpdateReactQuery.ts) with a writable atom plus `desktopBridge.onUpdateState`.
 4. Delete the old query-option tests.
 
 ## Public Interfaces And Types
@@ -70,8 +70,8 @@
 ## Test Plan
 - Add unit tests for `rpc/serverState.ts`: snapshot bootstrapping, stream replay, provider/settings updates.
 - Add unit tests for git/project/checkpoint hooks: loading, error mapping, retry behavior, invalidation, keep-previous-result behavior.
-- Update the browser harness in [wsRpcHarness.ts](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/apps/web/test/wsRpcHarness.ts) to assert direct RPC + atom behavior instead of `__resetNativeApiForTests`.
-- Replace [wsNativeApi.test.ts](/Users/julius/.t3/worktrees/codething-mvp/effect-http-router/apps/web/src/wsNativeApi.test.ts), `gitReactQuery.test.ts`, `providerReactQuery.test.ts`, and `desktopUpdateReactQuery.test.ts` with equivalent atom-backed coverage.
+- Update the browser harness in [wsRpcHarness.ts](apps/web/test/wsRpcHarness.ts) to assert direct RPC + atom behavior instead of `__resetNativeApiForTests`.
+- Replace [wsNativeApi.test.ts](apps/web/src/wsNativeApi.test.ts), `gitReactQuery.test.ts`, `providerReactQuery.test.ts`, and `desktopUpdateReactQuery.test.ts` with equivalent atom-backed coverage.
 - Acceptance scenarios:
 - welcome still bootstraps snapshot and navigation
 - keybindings toast still responds to config stream updates

diff --git a/apps/server/src/git/Layers/GitCore.ts b/apps/server/src/git/Layers/GitCore.ts
--- a/apps/server/src/git/Layers/GitCore.ts
+++ b/apps/server/src/git/Layers/GitCore.ts
@@ -1943,7 +1943,7 @@
       // Refresh upstream refs in the background so checkout remains responsive.
       yield* refreshCheckedOutBranchUpstream(input.cwd).pipe(
         Effect.ignoreCause({ log: true }),
-        Effect.forkDetach({ startImmediately: true }),
+        Effect.forkScoped,
       );
     },
   );

You can send follow-ups to this agent here.

juliusmarminge and others added 4 commits March 31, 2026 23:00
Co-authored-by: codex <codex@users.noreply.github.com>
- Use `wss` when the page is served over HTTPS
- Make transport/client disposal async so client scope closes before runtime teardown
- Update tests for secure-origin URL selection and disposal order
- Assert client scope closes before runtime disposal
- Use a mocked transport instance to keep ordering deterministic
@juliusmarminge juliusmarminge merged commit d8aa2f8 into main Apr 1, 2026
13 of 15 checks passed
@juliusmarminge juliusmarminge deleted the effect-http-router branch April 1, 2026 06:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants